package com.yc.jpyy.base.redis;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutionException;

import javax.xml.ws.Response;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.Pipeline;
import redis.clients.jedis.exceptions.JedisException;

import com.google.gson.reflect.TypeToken;
import com.yc.jpyy.base.util.BissinessException;
import com.yc.jpyy.base.util.JSONUtil;
import com.yc.jpyy.base.util.Serialize;

@SuppressWarnings("unchecked")
public class JedisTemplate implements IRedisManager {
	@SuppressWarnings("unused")
	private final static Logger logger = LoggerFactory.getLogger(JedisTemplate.class);
	private JedisPool jedisPool;
	private JedisPoolConfig config;

	private Integer maxTotal;
	private Integer maxIdle;
	private Integer waitMillis;
	private Integer timeout;
	private boolean testOnBorrow;
	private String ipAddress;
	private Integer port;
	private String password;

	public JedisTemplate(String password,String ip, Integer port, Integer maxTotal, Integer maxIdle, Integer waitMillis,Integer timeout, boolean testOnBorrow) {
		this.maxTotal = maxTotal;
		this.maxIdle = maxIdle;
		this.waitMillis = waitMillis;
		this.timeout = timeout;
		this.testOnBorrow = testOnBorrow;
		this.ipAddress = ip;
		this.port = port;
		this.password = password;
		System.out.println(" JedisTemplate  initialPool ipAddress :  " 
		                    + ipAddress +" =  port : " + port +" =  password : " + password);
		initialPool();
	}

	private void initialPool() {
		config = new JedisPoolConfig();
		config.setMaxTotal(maxTotal);
		config.setMaxIdle(maxIdle);
		config.setMaxWaitMillis(waitMillis);
		config.setTestOnBorrow(testOnBorrow);
	}

	private Jedis getJedis() {
		if (null == jedisPool) {
			jedisPool = new JedisPool(config, this.ipAddress, this.port, timeout);
		}
		return jedisPool.getResource();
	}

	public synchronized void deleteKey(String key) {
		Jedis jedis = null;
		boolean flag = true;
		try {
			jedis = getJedis();
			jedis.auth(password);
			jedis.del(key);
		} catch (JedisException e) {
			flag = false;
			jedisPool.returnBrokenResource(jedis);
			e.printStackTrace();
			throw e;
		} finally {
			if(jedisPool != null && jedis !=null && flag){
				jedisPool.returnResource(jedis);				
			}
		}
	}

	public synchronized void setKeyValue(final String key, final String value) throws BissinessException {
		Jedis jedis = null;
		boolean flag = true;
		try {
			jedis = getJedis();
			jedis.auth(password);
			jedis.set(key, value);
		} catch (JedisException e) {
			flag = false;
			jedisPool.returnBrokenResource(jedis);
			e.printStackTrace();
			throw e;
		} finally {
			if(jedisPool != null && jedis !=null && flag){
				jedisPool.returnResource(jedis);				
			}
		}
	}

	public synchronized String getKeyValue(final String key) {
		String value = null;
		Jedis jedis = null;
		boolean flag = true;
		try {
			jedis = getJedis();
			jedis.auth(password);
			value = jedis.get(key);
		} catch (JedisException e) {
			flag = false;
			jedisPool.returnBrokenResource(jedis);
			e.printStackTrace();
			throw e;
		} finally {
			if(jedisPool != null && jedis !=null && flag){
				jedisPool.returnResource(jedis);				
			}
		}

		return value;
	}

	@Override
	public synchronized void setKeyList(String key, List<String> list) throws BissinessException {
		deleteKey(key);
		Jedis jedis = null;
		boolean flag = true;
		try {
			jedis = getJedis();
			jedis.auth(password);
			for (int i = 0; i < list.size(); i++) {
				jedis.rpush(key, list.get(i));
			}
		} catch (JedisException e) {
			flag = false;
			jedisPool.returnBrokenResource(jedis);
			e.printStackTrace();
			throw e;
		} finally {
			if(jedisPool != null && jedis !=null && flag){
				jedisPool.returnResource(jedis);				
			}
		}
	}

	@Override
	public synchronized List<String> getKeyList(String key) throws BissinessException {
		List<String> value = new ArrayList<String>();
		Jedis jedis = null;
		boolean flag = true;
		try {
			jedis = getJedis();
			jedis.auth(password);
			if (jedis.exists(key)) {
				Long row = jedis.llen(key);
				value = jedis.lrange(key, 0, row);
			}
		} catch (JedisException e) {
			flag = false;
			jedisPool.returnBrokenResource(jedis);
			e.printStackTrace();
			throw e;
		} finally {
			if(jedisPool != null && jedis !=null && flag){
				jedisPool.returnResource(jedis);				
			}
		}
		return value;
	}
	
	@Override
	public synchronized List<String> getKeyList(String key, IRedisCacheEmptyHelper helperHand,HashMap<String,Object> empParam) throws BissinessException {
		List<String> value = new ArrayList<String>();
		value = getKeyList(key);
		if ((value.size() == 0) && (null != helperHand)){
			value = (List<String>)helperHand.doOperation(empParam);
		}
		return value;
	}

	@Override
	public synchronized void setKeyObject(final String key, final Object map) throws BissinessException {
		Jedis jedis = null;
		boolean flag = true;
		try {
			jedis = getJedis();
			jedis.auth(password);
			jedis.set(key.getBytes(), Serialize.serialize(map));
		} catch (JedisException e) {
			flag = false;
			jedisPool.returnBrokenResource(jedis);
			e.printStackTrace();
			throw e;
		} finally {
			if(jedisPool != null && jedis !=null && flag){
				jedisPool.returnResource(jedis);				
			}
		}
	}

	@Override
	public synchronized Object getKeyObject(final String key) throws BissinessException {
		Object value = null;
		Jedis jedis = null;
		boolean flag = true;
		try {
			jedis = getJedis();
			jedis.auth(password);
			if (jedis.exists(key.getBytes())) {
				value = (Object) Serialize.unserialize(jedis.get(key.getBytes()));
			}
		} catch (JedisException e) {
			flag = false;
			jedisPool.returnBrokenResource(jedis);
			e.printStackTrace();
			throw e;
		} finally {
			if(jedisPool != null && jedis !=null && flag){
				jedisPool.returnResource(jedis);				
			}
		}
		return value;
	}
	

	public static void main(String[] args) throws BissinessException {
		JedisTemplate client = new JedisTemplate("Admin2yunchuang2016","192.168.103.224", 6379, 10000, 5, 1000, 60000,false);
		String  sb = client.getKeyValue("gender");
		System.out.println(sb);
	}

	@SuppressWarnings("unused")
	private void clearDB() {
		Jedis jedis = null;
		boolean flag = true;
		try {
			jedis = getJedis();
			jedis.auth(password);
			jedis.flushDB();
		} catch (JedisException e) {
			flag = false;
			jedisPool.returnBrokenResource(jedis);
			e.printStackTrace();
			throw e;
		} finally {
			if(jedisPool != null && jedis !=null && flag){
				jedisPool.returnResource(jedis);				
			}
		}
	}

	@Override
	public synchronized void setKeyValueByList(List<RedisCacheBean> list) throws BissinessException {
		Jedis jedis = null;
		boolean flag = true;
		try {
			jedis = getJedis();
			jedis.auth(password);
			for (RedisCacheBean bean : list) {
				jedis.set(bean.getKey(), bean.getValue());
			}
		} catch (JedisException e) {
			flag = false;
			jedisPool.returnBrokenResource(jedis);
			e.printStackTrace();
			throw e;
		} finally {
			if(jedisPool != null && jedis !=null && flag){
				jedisPool.returnResource(jedis);				
			}
		}
	}

	@Override
	public synchronized void getKeyValueByList(List<RedisCacheBean> list) throws BissinessException {
		Jedis jedis = null;
		boolean flag = true;
		try {
			jedis = getJedis();
			jedis.auth(password);
			for (RedisCacheBean bean : list) {
				bean.setValue(jedis.get(bean.getKey()));
			}
		} catch (JedisException e) {
			flag = false;
			jedisPool.returnBrokenResource(jedis);
			e.printStackTrace();
			throw e;
		} finally {
			if(jedisPool != null && jedis !=null && flag){
				jedisPool.returnResource(jedis);				
			}
		}
	}

	@Override
	public void getKeyValueByList(List<RedisCacheBean> list, IRedisCacheEmptyHelper helperHand, HashMap<String, Object> empParam) throws BissinessException {
		getKeyValueByList(list);
		if (((null == list) || (list.size() == 0)) && (null != helperHand)){
			list = (List<RedisCacheBean>)helperHand.doOperation(empParam);
		}
	}

	@Override
	public Object getKeyObject(String key, IRedisCacheEmptyHelper helperHand, HashMap<String, Object> empParam) throws BissinessException {
		Object obj = getKeyObject(key);
		if ((null == obj) && (null != helperHand)){
			return helperHand.doOperation(empParam);
		}
		return obj;
	}

	@Override
	public String getKeyValue(String key, IRedisCacheEmptyHelper helperHand, HashMap<String, Object> empParam) throws BissinessException {
		String rts = getKeyValue(key);
		if ((null == rts) && (null != helperHand)){
			return (String)helperHand.doOperation(empParam);
		}
		return rts;
	}
	
	
	public synchronized Set<String> getKeys(String pattern)  {
		Jedis jedis = null;
		Set<String> keys = new HashSet<String>();
		boolean flag = true;
		try{
			jedis = getJedis();
			jedis.auth(password);
			keys = jedis.keys(pattern);
		} catch (JedisException e) {
			flag = false;
			jedisPool.returnBrokenResource(jedis);
			e.printStackTrace();
			throw e;
		} finally {
			if(jedisPool != null && jedis !=null && flag){
				jedisPool.returnResource(jedis);				
			}
		}
		return keys;
	}
	
	public synchronized Map<String,String> getKeyValueBatch(final List<String> keys) {
		Jedis jedis = null;
		Pipeline pipeline = null;
		boolean flag = true;
		Map<String,Response<String>> response = new HashMap<String,Response<String>>(keys.size());
		Map<String,String> result = new HashMap<String,String>();
		try {
			jedis = getJedis();
			jedis.auth(password);
			pipeline = jedis.pipelined();
			for(String key : keys){
				response.put(key, (Response<String>) pipeline.get(key));
			}
			pipeline.sync();
			for(String k: keys){
				result.put(k, response.get(k).get());
			}
		} catch (InterruptedException | ExecutionException e) {
			flag = false;
			pipeline = null;
			jedisPool.returnBrokenResource(jedis);
			e.printStackTrace();
		} catch (JedisException e) {
			flag = false;
			pipeline = null;
			jedisPool.returnBrokenResource(jedis);
			e.printStackTrace();
			throw e;
		} finally {
			response = null;
			if(jedisPool != null && jedis !=null && flag){
				jedisPool.returnResource(jedis);				
			}
		}
		return result;
	}
	
	
	public synchronized void deleteKey(final List<String> keys) {
		Jedis jedis = null;
		Pipeline pipeline = null;
		boolean flag = true;
		try {
			jedis = getJedis();
			jedis.auth(password);
			pipeline = jedis.pipelined();
			for(String key : keys){
				pipeline.del(key);
			}
			pipeline.sync();
		} catch (JedisException e) {
			flag = false;
			pipeline = null;
			jedisPool.returnBrokenResource(jedis);
			e.printStackTrace();
			throw e;
		} finally {
			if(jedisPool != null && jedis !=null && flag){
				jedisPool.returnResource(jedis);				
			}
		}
	}
}
